/*

RAT v0.5.0, Refractor2 Archive Tool

Copyright (C) 2002
					Tonto Rostenfaunt		tonto@linuxmail.org
					Blackjap McGee			blackjap@hawaii.rr.com

This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License
as published by the Free Software Foundation; either version 2
of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.

*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "rat.h"
#include "getopt.h"
#include "extract.h"
#include "pack.h"

#define RFAVER "Refractor2 FlatArchive 1.1  "
#define MAXRECORDS 15000
#define BLKSIZE 256
static float rfaversion=0.50;
static char* platform = "win32";

char *rfafile,*rfadir=".";
const char *exec_name;

//int packcontrol(void);
//int pack(char *, struct stat *, int);
int unpack(void);
void usage(char *);
int dirsetup(char name[512]);


int main(int argc,char **argv) {
 exec_name = argv[0];
 int gpt,pk=0,upk=0;

 while((gpt=getopt(argc,argv,"pud:g")) != -1) {
   switch(gpt) {
      case 'p':
        pk=1;
        break;
      case 'u':
        upk=1;
        break;
      case 'd':
        rfadir=optarg;
		  printf("untested, probably broken\n");
		  return -1;
        break;
	  case 'g':
		  printf("launching gui\n");
		  printf("not implemented\n");
		  return -1;
	    break;
      case ':':
        usage(argv[0]);
        exit(-1);
        break;
      case '?':
        usage(argv[0]);
        exit(-1);
        break;
   }
 }
 if((optind==argc) || (pk^upk)==0) {
   usage(argv[0]);
   exit(-1);
  }
 rfafile=argv[argc-1];

 if(pk==1) {
	const char *patterns[] = {".*", NULL};
	pack(argv[argc - 2], argv[argc - 1], patterns);
  }
 else if(upk==1) {
    unpack();
  }
 return(0);
}

void usage(char *argv0)
{
	printf("Version %.1f %s\n", rfaversion,platform);
	printf("Usage: %s [-u] [rfa archive]\n\t-u Unpack\n",argv0);
}

unsigned char *sbuff,*obuff;
int unpack(void)
{
 FILE *rfafd,*outfd;
 char *nbuf;
 long int offst=0,records=0,fpos=0;
 long int size=0,length=0,pos=0,tucsize=0;
 short int comp=1;
 char name[512],unused[12];

 rfafd = fopen(rfafile,"rb");
 if(rfafd==NULL) { perror("unpack:fopen()"); return -1; }

	 memset(&name,0,512);
 	fread(name,28,1,rfafd);
	if((strncmp(RFAVER,name,28))==0) {
		readu32(&offst,rfafd);
	} else { //1.2
		fseek(rfafd,0,SEEK_SET);
		readu32(&offst,rfafd);
	}
	fseek(rfafd,offst,SEEK_SET);
	readu32(&records,rfafd);
  	sbuff=malloc(49152);
	obuff=malloc(32772);

	//check if its compressed
   	memset(&name,0,512);
	pos=0; size=0; length=0;
   	if(readu32(&length,rfafd)!=1) { perror("unpack:for:fread(filename length)"); return -1; }
	// NOTE: No byteswapping for name as it's an ASCII string
   	if(fread(name,length,1,rfafd)!=1) { perror("unpack:for:fread(filename)"); return -1; }
   	if(readu32(&size,rfafd)!=1) { perror("unpack:for:fread(size)"); return -1; }
	if(readu32(&tucsize,rfafd)!=1) { perror("unpack:for:fread(tucsize)"); return -1; }
	if(size==tucsize) comp=0;
	fseek(rfafd,offst+4,SEEK_SET);

if(comp) {
	for(;records!=0;records--) {
    	memset(&name,0,512);
		pos=0; size=0; length=0;
    	if(readu32(&length,rfafd)!=1) { perror("unpack:for:fread(filename length)"); return -1; }
		// NOTE: No byteswapping for name as it's an ASCII string
    	if(fread(name,length,1,rfafd)!=1) { perror("unpack:for:fread(filename)"); return -1; }
    	if(readu32(&size,rfafd)!=1) { perror("unpack:for:fread(size)"); return -1; }
		if(readu32(&tucsize,rfafd)!=1) { perror("unpack:for:fread(tucsize)"); return -1; }
		if(readu32(&pos,rfafd)!=1) { perror("unpack:for:fseek(position)"); return -1; }
		if(fseek(rfafd,12,SEEK_CUR)==-1) { perror("unpack:for:fseek(skip unused)"); return -1; }
		printf(" Name length: %2ld\tFilename: %s\tOffset: %5ld\nSize: %5ld\tPosition: %lu\n", length, name, pos, size,fpos);
    	fpos=ftell(rfafd);
		dirsetup(name);
		extract(rfafd,name,tucsize,pos,sbuff,obuff);
	}
} else {	//no compression
	for(;records!=0;records--) {
	    memset(&name,0,512);
		pos=0; size=0; length=0;
   		if(readu32(&length,rfafd)!=1) { perror("unpack:for:fread(filename length)"); return -1; }
		// NOTE: No byteswapping for name as it's an ASCII string
  		if(fread(name,length,1,rfafd)!=1) { perror("unpack:for:fread(filename)"); return -1; }
   		if(readu32(&size,rfafd)!=1) { perror("unpack:for:fread(size)"); return -1; }
		if(readu32(&tucsize,rfafd)!=1) { perror("unpack:for:fread(tucsize)"); return -1; }
		if(readu32(&pos,rfafd)!=1) { perror("unpack:for:fseek(position)"); return -1; }
		if(fseek(rfafd,12,SEEK_CUR)==-1) { perror("unpack:for:fseek(skip unused)"); return -1; }
		printf(" Name length: %2ld\tFilename: %s\tOffset: %5ld\nSize: %5ld\tPosition: %lu\n", length, name, pos, size,fpos);
    	fpos=ftell(rfafd);
		dirsetup(name);
		outfd=fopen(name,"wb");
		nbuf=malloc(size);
		memset(nbuf,0,size);
		fseek(rfafd,pos,SEEK_SET);
		// No compression means no byte swapping, right? Right?
		fread(nbuf,(size_t)size,1,rfafd);
		fwrite(nbuf,(size_t)size,1,outfd);
		fseek(rfafd,fpos,SEEK_SET);
		fclose(outfd);
		free(nbuf);
	}
}
free(obuff);
 free(sbuff);
 fclose(rfafd);
 return 0;
}


int dirsetup(char name[])
{
	//max directory depth = 50

 char *cptr[50],path[512],cwd[512];
 int i=0,oldi;

 memcpy(path,name,512);
 getcwd(cwd,512);

 //bastard parser
 cptr[i]=strtok(path,"/");
 i++;
  while ((cptr[i]=strtok(NULL,"/")) != NULL) {
	 i++;
 }

 //directory creation
 i--;
 oldi=i;
 i=0;
 while(i<oldi) {
	if(chdir(cptr[i])!=0) {
		if((CreateDirectory(cptr[i],NULL)) ==0) {
			printf("failed to create directory!\n");
			return -1;
		}
		if(chdir(cptr[i])!=0) {
			printf("chdir failed\n");
			return -1;
		}
	}
	i++;
 }
 chdir(cwd);

 return 0;
}

